#include "tcpclient.h"
#include "ui_tcpclient.h"
#include <QMessageBox>

TcpClient::TcpClient(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::TcpClient)
{
    // 初始化界面
    ui->setupUi(this);

    // 初始化变量
    TotalBytes = 0;
    bytesReceived = 0;
    fileNameSize = 0;

    // 创建 TCP 客户端套接字
    tcpClient = new QTcpSocket(this);
    // 设置 TCP 端口
    tcpPort = 6666;

    // 连接 TCP 套接字的 readyRead 信号到 readMessage 槽函数
    connect(tcpClient, SIGNAL(readyRead()), this, SLOT(readMessage()));
    // 连接 TCP 套接字的 errorOccurred 信号到 displayError 槽函数
    connect(tcpClient, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
}

TcpClient::~TcpClient()
{
    // 析构函数，删除 UI 指针
    delete ui;
}

// 设置远程服务器地址并发起新连接
void TcpClient::setHostAddress(QHostAddress address)
{
    // 保存远程服务器地址
    hostAddress = address;
    newConnect();
}

// 设置要接收的文件名，并打开相应的文件
void TcpClient::setFileName(QString fileName)
{
    // 创建本地文件对象
    localFile = new QFile(fileName);
}

// 处理窗口关闭事件
void TcpClient::closeEvent(QCloseEvent *)
{
    // 调用关闭按钮点击事件处理函数
    on_tcpClientCloseBtn_clicked();
}

// 发起新连接的函数
void TcpClient::newConnect()
{
    // 重置数据块大小
    blockSize = 0;
    // 中止之前的连接
    tcpClient->abort();
    // 连接到远程服务器
    tcpClient->connectToHost(hostAddress, tcpPort);
    // 开始计时
    time.start();
}

// 读取消息的槽函数
void TcpClient::readMessage()
{
    // 使用 QDataStream 从 TCP 套接字读取数据
    QDataStream in(tcpClient);
    // 设置 QDataStream 的版本
    in.setVersion(QDataStream::Qt_6_7);

    // 计算从开始接收数据到现在的时间
    float useTime = time.elapsed();

    // 首次读取数据，分两部分：总数据大小和文件名大小
    if (bytesReceived <= sizeof(qint64) * 2) {
        if ((tcpClient->bytesAvailable() >= sizeof(qint64)*2) && (fileNameSize == 0)) {
            // 读取总数据大小（字节 0-7）
            in >> TotalBytes;
            // 读取文件名大小（字节 8-15）
            in >> fileNameSize;
            bytesReceived += sizeof(qint64)*2;
        }

        // 读取文件名
        if ((tcpClient->bytesAvailable() >= fileNameSize) && (fileNameSize!= 0)) {
            // 读取文件名（从字节 15 开始）
            in >> fileName;
            bytesReceived += fileNameSize;
            // 尝试打开文件进行写入
            if (!localFile->open(QFile::WriteOnly)) {
                QMessageBox::warning(this,tr("应用程序"),tr("无法读取文件 %1:\n%2.").arg(fileName).arg(localFile->errorString()));
                return;
            }
        } else {
            return;
        }
    }

    // 读取文件数据
    if (bytesReceived < TotalBytes) {
        // 累计已接收字节数
        bytesReceived += tcpClient->bytesAvailable();
        // 读取所有可用数据
        inBlock = tcpClient->readAll();
        // 将数据写入文件
        localFile->write(inBlock);
        inBlock.resize(0);
    }

    // 设置进度条的最大值和当前值
    ui->progressBar->setMaximum(TotalBytes);
    ui->progressBar->setValue(bytesReceived);

    // 计算接收速度和剩余时间等信息
    double speed = bytesReceived / useTime;
    ui->clientStatusLabel->setText(tr("已接收 %1MB (%2MB/s)\n共%3MB 已用时:%4秒\n估计剩余时间：%5秒")
                                       .arg(bytesReceived / (1024*1024))
                                       .arg(speed*1000/(1024*1024),0,'f',2)
                                       .arg(TotalBytes / (1024 * 1024))
                                       .arg(useTime/1000,0,'f',0)
                                       .arg(TotalBytes/speed/1000 - useTime/1000,0,'f',0));
    if (bytesReceived == TotalBytes) {
        // 接收完成，关闭文件和连接
        localFile->close();
        tcpClient->close();
        ui->clientStatusLabel->setText(tr("接收文件 %1 完毕").arg(fileName));
    }
}

// 显示错误信息
void TcpClient::displayError(QAbstractSocket::SocketError errorr)
{
    qDebug() << errorr;
}

// 取消接收文件
void TcpClient::on_tcpClientCancelBtn_clicked()
{
    // 中止 TCP 连接
    tcpClient->abort();
    // 如果文件已打开，关闭文件
    if (localFile->isOpen())
        localFile->close();
}


// 关闭客户端窗口
void TcpClient::on_tcpClientCloseBtn_clicked()
{
    // 中止 TCP 连接
    tcpClient->abort();
    // 如果文件已打开，关闭文件
    if (localFile->isOpen())
        localFile->close();
    // 关闭窗口
    close();
}
